package com.piggy.logi.sys.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.piggy.common.core.utils.PageUtils;
import com.piggy.common.core.web.page.PagePlus;
import com.piggy.common.core.web.page.TableDataInfo;
import com.piggy.logi.sys.bo.LogiAgentPayStatisticsQueryBo;
import com.piggy.logi.sys.bo.LogiReceivableStatisticsQueryBo;
import com.piggy.logi.sys.domain.*;
import com.piggy.logi.sys.enums.CheckBillStatusEnum;
import com.piggy.logi.sys.service.*;
import com.piggy.logi.sys.vo.LogiAgentPayStatisticsVo;
import com.piggy.logi.sys.vo.LogiReceivableStatisticsVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 财务统计Service业务层处理
 *
 * @author fengxy
 * @date 2023/10/17 21:54
 **/
@Slf4j
@Service
public class LogiFinanceStatisticsServiceImpl implements ILogiFinanceStatisticsService {

    @Resource
    private ILogiCustomerService logiCustomerService;

    @Resource
    private ILogiWaybillService logiWaybillService;

    @Resource
    private ILogiWaybillGoodSourceService logiWaybillGoodSourceService;

    @Resource
    private ILogiWaybillValueAddService logiWaybillValueAddService;

    @Resource
    private ILogiWaybillReceivableService logiWaybillReceivableService;

    @Resource
    private ILogiWaybillAgentPayService logiWaybillAgentPayService;

    @Override
    public TableDataInfo<LogiReceivableStatisticsVo> receivableStatisticsPage(LogiReceivableStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<Long> waybillIds = completedWaybills.stream().map(LogiWaybill::getWaybillId).distinct().collect(Collectors.toList());
        List<LogiWaybillReceivable> waybillReceivableList = logiWaybillReceivableService.list(Wrappers.lambdaQuery(LogiWaybillReceivable.class).in(LogiWaybillReceivable::getWaybillId, CollUtil.isEmpty(waybillIds) ? CollUtil.newArrayList(0L) : waybillIds));
        PagePlus<LogiCustomer, LogiReceivableStatisticsVo> result = logiCustomerService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, waybillReceivableList), LogiReceivableStatisticsVo.class);
        List<LogiReceivableStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills, waybillReceivableList);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiReceivableStatisticsVo> receivableStatisticsList(LogiReceivableStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<Long> waybillIds = completedWaybills.stream().map(LogiWaybill::getWaybillId).distinct().collect(Collectors.toList());
        List<LogiWaybillReceivable> waybillReceivableList = logiWaybillReceivableService.list(Wrappers.lambdaQuery(LogiWaybillReceivable.class).in(LogiWaybillReceivable::getWaybillId, CollUtil.isEmpty(waybillIds) ? CollUtil.newArrayList(0L) : waybillIds));
        List<LogiReceivableStatisticsVo> result = logiCustomerService.listVo(buildQueryWrapper(bo, waybillReceivableList), LogiReceivableStatisticsVo.class);
        fillData(result, bo, completedWaybills, waybillReceivableList);
        return result;
    }

    @Override
    public TableDataInfo<LogiAgentPayStatisticsVo> agentPayStatisticsPage(LogiAgentPayStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<Long> waybillIds = completedWaybills.stream().map(LogiWaybill::getWaybillId).distinct().collect(Collectors.toList());
        List<LogiWaybillAgentPay> waybillAgentPayList = logiWaybillAgentPayService.list(Wrappers.lambdaQuery(LogiWaybillAgentPay.class).in(LogiWaybillAgentPay::getWaybillId, CollUtil.isEmpty(waybillIds) ? CollUtil.newArrayList(0L) : waybillIds));
        PagePlus<LogiCustomer, LogiAgentPayStatisticsVo> result = logiCustomerService.pageVo(PageUtils.buildPagePlus(bo, true), buildQueryWrapper(bo, waybillAgentPayList), LogiAgentPayStatisticsVo.class);
        List<LogiAgentPayStatisticsVo> pageListVos = result.getRecordsVo();
        fillData(pageListVos, bo, completedWaybills, waybillAgentPayList);
        result.setRecordsVo(pageListVos);
        return PageUtils.buildDataInfo(result);
    }

    @Override
    public List<LogiAgentPayStatisticsVo> agentPayStatisticsList(LogiAgentPayStatisticsQueryBo bo) {
        List<LogiWaybill> completedWaybills = logiWaybillService.getCompletedWaybills(bo.getDeptId(), bo.getStartDate(), bo.getEndDate());
        List<Long> waybillIds = completedWaybills.stream().map(LogiWaybill::getWaybillId).distinct().collect(Collectors.toList());
        List<LogiWaybillAgentPay> waybillAgentPayList = logiWaybillAgentPayService.list(Wrappers.lambdaQuery(LogiWaybillAgentPay.class).in(LogiWaybillAgentPay::getWaybillId, CollUtil.isEmpty(waybillIds) ? CollUtil.newArrayList(0L) : waybillIds));
        List<LogiAgentPayStatisticsVo> result = logiCustomerService.listVo(buildQueryWrapper(bo, waybillAgentPayList), LogiAgentPayStatisticsVo.class);
        fillData(result, bo, completedWaybills, waybillAgentPayList);
        return result;
    }

    /**
     * 组装查询条件 - 应收统计
     **/
    private Wrapper<LogiCustomer> buildQueryWrapper(LogiReceivableStatisticsQueryBo bo, List<LogiWaybillReceivable> waybillReceivableList) {
        LambdaQueryWrapper<LogiCustomer> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getCustomerName()), LogiCustomer::getCustomerName, bo.getCustomerName());
        // 客户id集合
        List<Long> customerIds = waybillReceivableList.stream().map(LogiWaybillReceivable::getPayerId).collect(Collectors.toList());
        lqw.in(LogiCustomer::getCustomerId, CollUtil.isEmpty(customerIds) ? CollUtil.newArrayList(0) : customerIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 应收统计
     **/
    private void fillData(List<LogiReceivableStatisticsVo> pageListVos, LogiReceivableStatisticsQueryBo bo, List<LogiWaybill> completedWaybills, List<LogiWaybillReceivable> waybillReceivableList) {
        pageListVos.parallelStream().forEach(a -> {
            // 查询符合条件的代收记录
            List<LogiWaybillReceivable> receivableList = waybillReceivableList.stream().filter(b -> b.getPayerId().equals(a.getCustomerId())).collect(Collectors.toList());
            // 设置关联运单数量
            a.setWaybillNum(receivableList.size());
            // 设置对账合计、已对账合计、未对账合计、未结算金额、已结算金额
            BigDecimal totalAmount = BigDecimal.ZERO, checkedAmount = BigDecimal.ZERO, noCheckAmount = BigDecimal.ZERO,
                    settledAmount = BigDecimal.ZERO, noSettleAmount = BigDecimal.ZERO;
            for (LogiWaybillReceivable receivable : receivableList) {
                totalAmount = totalAmount.add(receivable.getTradeAmount());
                if (receivable.getCheckBillStatus() == CheckBillStatusEnum.CHECKED.getCode()) {
                    checkedAmount = checkedAmount.add(receivable.getReceivableAmount());
                } else {
                    noCheckAmount = noCheckAmount.add(receivable.getReceivableAmount());
                }
                settledAmount = settledAmount.add(receivable.getRealAmount());
                noSettleAmount = noSettleAmount.add(receivable.getReceivableBalance());
            }
            a.setTotalAmount(totalAmount);
            a.setCheckedAmount(checkedAmount);
            a.setNoCheckAmount(noCheckAmount);
            a.setSettledAmount(settledAmount);
            a.setNoSettleAmount(noSettleAmount);
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }

    /**
     * 组装查询条件 - 代收货款统计
     **/
    private Wrapper<LogiCustomer> buildQueryWrapper(LogiAgentPayStatisticsQueryBo bo, List<LogiWaybillAgentPay> waybillAgentPayList) {
        LambdaQueryWrapper<LogiCustomer> lqw = Wrappers.lambdaQuery();
        lqw.like(StrUtil.isNotBlank(bo.getCustomerName()), LogiCustomer::getCustomerName, bo.getCustomerName());
        // 客户id集合
        List<Long> customerIds = waybillAgentPayList.stream().map(LogiWaybillAgentPay::getPayerId).collect(Collectors.toList());
        lqw.in(LogiCustomer::getCustomerId, CollUtil.isEmpty(customerIds) ? CollUtil.newArrayList(0) : customerIds);
        return lqw;
    }

    /**
     * 补充字段数据 - 代收货款统计
     **/
    private void fillData(List<LogiAgentPayStatisticsVo> pageListVos, LogiAgentPayStatisticsQueryBo bo, List<LogiWaybill> completedWaybills, List<LogiWaybillAgentPay> waybillAgentPayList) {
        pageListVos.parallelStream().forEach(a -> {
            // 查询符合条件的代付记录
            List<LogiWaybillAgentPay> agentPayList = waybillAgentPayList.stream().filter(b -> b.getPayerId().equals(a.getCustomerId())).collect(Collectors.toList());
            // 设置关联运单数量
            a.setWaybillNum(agentPayList.size());
            // 运单id集合
            List<Long> waybillIds = agentPayList.stream().map(LogiWaybillAgentPay::getWaybillId).collect(Collectors.toList());
            // 查询符合条件已完成的运单
            List<LogiWaybill> waybillList = completedWaybills.stream().filter(b -> waybillIds.contains(b.getWaybillId()) && b.getDeptId().equals(a.getDeptId())).collect(Collectors.toList());
            // 货物明细
            List<LogiWaybillGoodSource> goodSourceList = logiWaybillGoodSourceService.getByWaybillIds(waybillIds);
            // 完成出货量（吨）
            List<Long> completedWaybillIds = waybillList.stream().filter(b -> b.getRefund() == 0).map(LogiWaybill::getWaybillId).collect(Collectors.toList());
            BigDecimal finishShipQuality = goodSourceList.stream().filter(b -> completedWaybillIds.contains(b.getWaybillId()) && StrUtil.isNotBlank(b.getWeight())).map(b -> new BigDecimal(b.getWeight())).reduce(BigDecimal.ZERO, BigDecimal::add);
            a.setFinishShipQuality(finishShipQuality);
            //
            List<LogiWaybillValueAdd> waybillValueAddList = logiWaybillValueAddService.getByWaybillIds(waybillIds);
            // 设置代收金额、服务费
            BigDecimal agentBusinessFee = BigDecimal.ZERO, agentBusinessServiceFee = BigDecimal.ZERO;
            for (LogiWaybillValueAdd waybillValueAdd : waybillValueAddList) {
                agentBusinessFee = agentBusinessFee.add(waybillValueAdd.getAgentBusinessFee());
                agentBusinessServiceFee = agentBusinessServiceFee.add(waybillValueAdd.getAgentBusinessServiceFee());
            }
            a.setAgentBusinessFee(agentBusinessFee);
            a.setAgentBusinessServiceFee(agentBusinessServiceFee);
            // 设置实收金额、实收余额
            BigDecimal realAmount = BigDecimal.ZERO, realBalance = BigDecimal.ZERO;
            for (LogiWaybillAgentPay agentPay : agentPayList) {
                realAmount = realAmount.add(agentPay.getRealAmount());
                realBalance = realAmount.add(agentPay.getRealBalance());
            }
            a.setRealAmount(realAmount);
            a.setRealBalance(realBalance);
            // 时间范围
            if (ObjectUtil.isAllNotEmpty(bo.getStartDate(), bo.getEndDate())) {
                a.setTimeFrame(DateUtil.formatDate(DateUtil.parse(bo.getStartDate())) + " - " + DateUtil.formatDate(DateUtil.parse(bo.getEndDate())));
            } else {
                a.setTimeFrame("至今");
            }
        });
    }
}
